/* 
 * This class implements a table that takes as input the names of various
 * components of a chemical equation and the following related data:
 * species:
 * * Whether this is a free component or not
 * * Initial Molarity 
 * * Free Molarity Guess (if this is not a free component)
 *
 * Author: Aaron A. Lovato
 */
package gui;

import javax.swing.table.*;
import java.util.*;
import javax.swing.event.*;
import core.SystemController;
import core.Component;

public class ComponentTableModel extends AbstractTableModel 
                                implements TableModelListener, Observer
{
    protected ResourceBundle resbundle;
    private String[] columns;
    private Object[][] data;
    private UnicodeTranslator translator;
    private SystemController controller;
    private boolean updateSystem;
    private boolean uninitialized;
    
    public ComponentTableModel(SystemController controller)
    {
        // The ResourceBundle below contains all of the strings used in this application. 
        // New localities can be added by adding additional properties files.
        resbundle = ResourceBundle.getBundle ("strings", Locale.getDefault());

        //Set up the translator
        translator = new UnicodeTranslator();

        //Set up the controller
        this.controller = controller;
        controller.addObserver(this);
        updateSystem = false;
        uninitialized = true;
        
        columns = new String[5];
        columns[0] = resbundle.getString("component");
        columns[1] = resbundle.getString("state");
        columns[2] = resbundle.getString("freeComponent");
        columns[3] = resbundle.getString("initialConcentration");
        columns[4] = resbundle.getString("freeConcGuess"); 
        
        data = new Object[1][5];
        data[0][0] = new String("");
        data[0][1] = new String("");
        data[0][2] = true;
        data[0][3] = new Double(0.0);
        data[0][4] = new Double(0.0);
        
        addTableModelListener(this);
        fireTableRowsInserted(0, 0);
        updateSystem = true;
    }
    
    public int getColumnCount()
    {
        return columns.length;
    }
    
    public int getRowCount()
    {
        return data.length;
    }
    
    public String getColumnName(int col) 
    {
        return columns[col];
    }

    public Object getValueAt(int row, int col) 
    {
        return data[row][col];
    }
    
    public Class getColumnClass(int c) 
    {
        return getValueAt(0, c).getClass();
    }

    public boolean isCellEditable(int row, int col) 
    {
        if(data[row][2].equals(true) && col == 3)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    public void setValueAt(Object value, int row, int col) 
    {
        data[row][col] = value;
        fireTableCellUpdated(row, col);
    }
    
    public void addRow(Object[] row)
    {
        int newLength;

        int offset = 0;
        if(data[0][0] == null)
        {
            offset = 0;
        }
        else
        {
            offset = 1;
        }
        newLength = data.length + offset;
        Object[][] newData = new Object[newLength][5];
        
        System.arraycopy(data, 0, newData, offset, data.length);
        data = newData;
        data[0][0] = row[0];
        data[0][1] = row[1];
        data[0][2] = row[2];
        data[0][3] = row[3];
        data[0][4] = row[4];

        fireTableRowsInserted(0, 0);
    }
    
    public void tableChanged(TableModelEvent e)
    {
        //Extend the table when a new row is filled
        if(e.getType() == TableModelEvent.UPDATE && e.getFirstRow() == 0)
        {
            Object[] newRow = new Object[5];
            newRow[0] = new String();
            newRow[1] = new String();
            newRow[2] = false;
            newRow[3] = new Double(0.0);
            newRow[4] = new Double(0.0);
            addRow(newRow);
        }

        //Translate component names to unicode
        String currentEq;
        for(int index = e.getFirstRow(); index < data.length; index++)
        {
            if(data[index][0] != null)
            {
                currentEq = data[index][0].toString();
                currentEq = translator.translate(currentEq);
                data[index][0] = currentEq;
            }
        }
        
        //Update the system's components
        if(updateSystem)
        {
            controller.clearComponents();
            for(int index = 0; index < data.length; index++)
            {
                if(data[index][0] != null)
                {
                    controller.addComponent((String)data[index][0], (String)data[index][1], 
                                            (Double)data[index][3], (Double)data[index][4]);
                }
            }
        }

    }
    
    public void update(Observable controller, Object arg)
    {
        updateSystem = false;
        //Re-build the data in the table
        data = new Object[1][5];
        Vector<Component> components = this.controller.getComponents();
        for(Component temp : components)
        {
            Object[] newRow = new Object[5];
            newRow[0] = temp.getName();
            if(temp.getType() != null)
            {
                newRow[1] = temp.getType().toString();
            }
            else
            {
                newRow[1] = "";
            }
            newRow[2] = temp.isFree();
            newRow[3] = temp.getTotalMolarity();
            newRow[4] = temp.getFreeMolarity();
            addRow(newRow);
        }
        fireTableDataChanged();
        updateSystem = true;
    }
    
}